import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashSet;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;

public class ChatServer {
	private static final int PORT = 2828;
	private static HashSet<String> names = new HashSet<String>();
	private static HashSet<PrintWriter> writers = new HashSet<PrintWriter>();
	private static ConcurrentHashMap<String, PrintWriter> userMap = new ConcurrentHashMap<String, PrintWriter>();
	public static final String NAME = "NAME";
	public static final String NAME_UNIQUE = "UNIQUE_NAME";
	public static final String MESSAGE = "MESSAGE ";
	public static final String CHATTER_LIST = "CHATTER_NUM";
	public static final String WHISPER = "WHISPERZ";
	public static final int TARGET_NAME_IDX = 0;
	public static final int SRC_NAME_IDX = 1;
	public static final int MSG_IDX = 2;

	public static void main(String[] args) throws Exception {
		System.out.println("채팅서버 oN...");
		ServerSocket listener = new ServerSocket(PORT);
		try {
			while (true) {
				new Handler(listener.accept()).start();
			}
		} finally {
			listener.close();
		}
	}

	private static class Handler extends Thread {
		private String name;
		private Socket socket;
		private BufferedReader in;
		private PrintWriter out;
		private boolean isFirst = true;

		public Handler(Socket socket) {
			this.socket = socket;
		}

		public void run() {
			try {
				in = new BufferedReader(new InputStreamReader(
						socket.getInputStream()));
				out = new PrintWriter(socket.getOutputStream(), true);
				while (true) {
					out.println(NAME);
					name = in.readLine();
					if (name == null) {
						return;
					}
					synchronized (names) {
						if (!names.contains(name)) {
							names.add(name);
							break;
						}
					}
				}

				if (isFirst) {
					userMap.put(name, out);
					isFirst = false;
				}

				out.println(NAME_UNIQUE);
				writers.add(out);
				userRefresh();

				while (true) {
					String input = in.readLine();
					if (input == null) {
						return;
					}
					// 귓속말 체크
					if (input.contains(WHISPER)) {
						String[] whisperInfo = getWhisperInfo(input);
						if (whisperInfo == null)
							return;

						PrintWriter printWriter = userMap
								.get(whisperInfo[TARGET_NAME_IDX]);
						if (printWriter == null)
							return;

						printWriter.println(WHISPER + "귓속말(" + whisperInfo[SRC_NAME_IDX]
								+ ") -> " + whisperInfo[MSG_IDX]);

					} else {
						for (PrintWriter writer : writers) {
							writer.println(MESSAGE + name + ": " + input);
						}
					}
				}
			} catch (IOException e) {
				System.out.println(e);
			} finally {
				if (name != null) {
					names.remove(name);
					out.println(CHATTER_LIST + names);
				}
				if (out != null) {
					writers.remove(out);
				}
				try {
					socket.close();
				} catch (IOException e) {
				}
			}
		}

		private String[] getWhisperInfo(String input) {
			String[] split = input.split(",");

			String targetName = split[1];
			String srcName = split[2];

			if (!names.contains(targetName))
				return null;

			StringBuffer msg = new StringBuffer();
			for (int i = 3; i < split.length; i++) {
				msg.append(split[i]);
			}

			String[] result = new String[3];

			result[TARGET_NAME_IDX] = targetName;
			result[SRC_NAME_IDX] = srcName;
			result[MSG_IDX] = msg.toString();

			return result;
		}

		private void userRefresh() {
			for (PrintWriter writer : writers) {
				writer.println(CHATTER_LIST + names);
			}
		}
	}
}